#include "procmontiondection.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef __ANDROID__
#include <assert.h>
#include <pthread.h>
#include <unistd.h>
#include<android/bitmap.h>
#include <android/log.h>
#endif

#include <jni.h>

typedef struct {
	unsigned char alpha;
	unsigned char red;
	unsigned char green;
	unsigned char blue;
} argb;

static JavaVM * g_jvm;
#define ZKUTools_JNIFUNC(name)  JNIEXPORT Java_com_zkteco_UTools_ProcmontionDection_##name




#pragma pack (1)
typedef struct tagBITMAPINFOHEADER{
	unsigned int      biSize;
	int       biWidth;
	int       biHeight;
	unsigned short       biPlanes;
	unsigned short       biBitCount;
	unsigned int      biCompression;
	unsigned int      biSizeImage;
	int       biXPelsPerMeter;
	int       biYPelsPerMeter;
	unsigned int      biClrUsed;
	unsigned int      biClrImportant;
} BITMAPINFOHEADER, *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;


typedef struct tagRGBQUAD {
	unsigned char    rgbBlue;
	unsigned char    rgbGreen;
	unsigned char    rgbRed;
	unsigned char    rgbReserved;
} RGBQUAD;
typedef RGBQUAD *LPRGBQUAD;

typedef struct tagBITMAPFILEHEADER {
	unsigned short    bfType;
	unsigned int   bfSize;
	unsigned short    bfReserved1;
	unsigned short    bfReserved2;
	unsigned int   bfOffBits;
} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;


typedef struct tagBITMAPINFO {
	BITMAPINFOHEADER    bmiHeader;
	RGBQUAD             bmiColors[1];
} BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
#pragma pack()



int WriteBitmapHeader(unsigned char *Buffer, int Width, int Height)
{
	BITMAPFILEHEADER *bmpfheader=(BITMAPFILEHEADER *)Buffer;
	BITMAPINFO *bmpinfo=(BITMAPINFO *)(((char*)bmpfheader)+14);
	int i,w;
	memset(bmpfheader,0,0x500);
	bmpfheader->bfType =19778;
	w = ((Width+3)/4)*4*Height+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFO)+255*sizeof(RGBQUAD);
	memcpy((void*)(((char*)bmpfheader)+2), &w, 4);
	//bmpfheader->bfOffBits;
	w= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFO)+255*sizeof(RGBQUAD);
	memcpy((void*)(((char*)bmpfheader)+10), &w, 4);
	bmpinfo->bmiHeader.biWidth=Width;
	bmpinfo->bmiHeader.biHeight=Height;
	bmpinfo->bmiHeader.biBitCount=8;
	bmpinfo->bmiHeader.biClrUsed=0;
	bmpinfo->bmiHeader.biSize=sizeof(bmpinfo->bmiHeader);
	bmpinfo->bmiHeader.biPlanes=1;
	bmpinfo->bmiHeader.biSizeImage=((Width+3)/4)*4*Height;
	for(i=1;i<256;i++)
	{
		bmpinfo->bmiColors[i].rgbBlue=i;
		bmpinfo->bmiColors[i].rgbGreen=i;
		bmpinfo->bmiColors[i].rgbRed=i;
	}
	return sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
}

int WriteBitmap(unsigned char *buffer, int Width, int Height, const char* filename)
{
    FILE* pFile = fopen(filename, "wb+");
    if (NULL == pFile)
    {
        return -1;
    }
    
	unsigned char Buffer[0x500];
	int i, w;
	int nHeadLen = WriteBitmapHeader(Buffer, Width, Height);
	int nPos = 0;
	fwrite(Buffer, 1, nHeadLen, pFile);
	nPos += nHeadLen;
	w = ((Width+3)/4)*4;
	buffer+=Width*(Height-1);
	unsigned char bufFill[4];
	memset(bufFill, 0xFF, 4);
	for(i=0; i<Height; i++)
	{
        fwrite(buffer, 1, Width, pFile);
		nPos+= Width;
		if(w-Width)
		{
            fwrite(bufFill, 1, w-Width, pFile);
			nPos+= w-Width;
		}
		buffer-=Width;
	}
    fclose(pFile);
	return 1;
}	

#ifdef __cplusplus
extern "C"
{
#endif

jint ZKUTools_JNIFUNC(dection)(JNIEnv *env, jclass obj, jint opType, jbyteArray grayBuffer, jint width, jint height)
{
	jbyte* temp_grayBuffer = NULL;
    if (NULL != grayBuffer)
    {
        temp_grayBuffer = (jbyte*)env->GetByteArrayElements(grayBuffer, NULL);
    }
	int ret = ProcMotionDetection(opType, (unsigned char*)temp_grayBuffer, width, height);
	if (NULL != temp_grayBuffer)	
	{		
		env->ReleaseByteArrayElements(grayBuffer, temp_grayBuffer, 0);	
	}
	return ret;
}


jint ZKUTools_JNIFUNC(dectionFromBitmap)(JNIEnv *env, jclass obj, jint opType, jobject bitmapObj)
{
#ifdef __ANDROID__
	unsigned char* temp_grayBuffer = NULL;
    int* dataFromBmp = NULL;
    int bmpWidth = 0;
    int bmpHeight = 0;
    if (NULL != bitmapObj)
    {
        AndroidBitmapInfo bmpInfo={0};
        if(AndroidBitmap_getInfo(env,bitmapObj,&bmpInfo) >= 0)
        {
            if (bmpInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
            {
                return -1;
            }
            AndroidBitmap_lockPixels(env,bitmapObj,(void**)&dataFromBmp);
            if(NULL != dataFromBmp)
            {
                bmpWidth = bmpInfo.width;
                bmpHeight = bmpInfo.height;
                temp_grayBuffer = new unsigned char[bmpInfo.width*bmpInfo.height];
                unsigned char* pixelsgray = (unsigned char*)temp_grayBuffer;
                for (int y = 0; y < bmpInfo.height; y++) {
                    argb* line = (argb *) dataFromBmp;
                    unsigned char * grayline = (unsigned char *) pixelsgray;
                    for (int x = 0; x < bmpInfo.width; x++) {
                        grayline[x] = (line[x].red + line[x].green + line[x].blue) / 3;
                    }
                    dataFromBmp = (int*)((unsigned char *) dataFromBmp + bmpInfo.stride);
                    pixelsgray = (unsigned char *) pixelsgray + bmpInfo.width;
                }
            }
        }
    }
	int ret = ProcMotionDetection(opType, (unsigned char*)temp_grayBuffer, bmpWidth, bmpHeight);
	if (NULL != dataFromBmp)
    {
        AndroidBitmap_unlockPixels(env,bitmapObj);
    }
    if (NULL != temp_grayBuffer)	
	{		
		delete[] temp_grayBuffer;
	}
	return ret;
#else
    return -1;
#endif
}


#ifdef __cplusplus
};
#endif


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {

	jint result = -1;
	
	g_jvm = vm;
	result = JNI_VERSION_1_4;

	return result;
}

